package br.com.wepa.webapps.orca.controle.actions.struts;

import java.util.Stack;

import javax.servlet.http.HttpServletRequest;

import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;

import br.com.wepa.webapps.orca.controle.ConstantesControle;
import br.com.wepa.webapps.orca.controle.ControleWeb;

public class ActionTracer implements ConstantesControle {

	private LimitedtStack stack;

	public ActionTracer() {
		stack = new LimitedtStack();
	}

	public ActionTracer(int limit) {
		stack = new LimitedtStack(limit);
	}

	/**
	 * Push an action ActionEvent called by this request
	 * 
	 * @param request
	 * @param form
	 * @throws Exception
	 * @throws Exception
	 */
	public void push(HttpServletRequest request, ActionForm form,ActionMapping mapping)
			throws Exception {
		this.push(createRequestActionEvent(request, form, mapping));
	}

	/**
	 * Push an action ActionEvent with this path and form
	 * 
	 * @param path
	 * @param form
	 * @throws Exception
	 */
	public void push(ActionForm form, ActionMapping mapping,String path) throws Exception {
		if (path != null) {
			this.push(form,mapping,newActionForward(path));
		}
	}

	/**
	 * Push an action ActionEvent with this forward and form
	 * 
	 * @param forward
	 * @param form
	 * @throws Exception
	 */
	public void push(ActionForm form,ActionMapping mapping, ActionForward forward) {
		this.push(createActionEvent(form,mapping,forward));
	}

	/**
	 * Push an action ActionEvent
	 * 
	 * @param ActionEvent
	 * @throws Exception
	 */
	public void push(ActionEvent event) {
		this.stack.push(event);
	}

	/**
	 * Returns the top of the stack history without pop.
	 * 
	 * @param form
	 * @throws Exception
	 */
	public ActionEvent getLast() {
		return stack.peek();
	}

	/**
	 * Pop the last Action of the stack
	 * 
	 * @param form
	 * @throws Exception
	 */
	public ActionEvent pop() {
		return stack.pop();
	}

	/**
	 * Remove the object at index
	 * 
	 * @param form
	 * @throws Exception
	 */
	public ActionEvent remove(int i) {
		return stack.remove(i);
	}

	
	/**
	 * Returns an ActionForward with the path specified to call an action
	 * 
	 * @param actionCall
	 * @return
	 */
	public static ActionForward newActionForward(String actionCall) {
		return new ActionForward(actionCall);
	}

	/**
	 * Return the size
	 * 
	 * @return
	 */
	public int size() {
		return stack.size();
	}

	/**
	 * Creates an action event called by this request
	 * @param request
	 * @param form
	 * @param mapping
	 * @return
	 */
	public static ActionEvent createRequestActionEvent(HttpServletRequest request,ActionForm form,ActionMapping mapping) {
		ActionForward actionCall = ActionTracer.newActionForward(ControleWeb.mountActionCall(request));		
		return ActionTracer.createActionEvent(form, mapping, actionCall);
	}
	
	/**
	 * Creates an action event
	 * @param form
	 * @param mapping
	 * @param forward
	 * @return
	 */
	public static ActionEvent createActionEvent(ActionForm form,ActionMapping mapping, ActionForward forward) {
		return new ActionEvent(form,mapping,forward);
	}

	/**
	 * Return if is empty
	 * 
	 * @return
	 */
	public boolean isEmpty() {
		return stack.isEmpty();
	}

	private class LimitedtStack {
		private Stack<ActionEvent> stack = new Stack<ActionEvent>();

		private Integer limit = Integer.MAX_VALUE;

		private boolean islimited = false;

		public LimitedtStack() {
		}

		public boolean isEmpty() {
			return stack.isEmpty();
		}

		public int size() {
			return stack.size();
		}

		public ActionEvent peek() {
			return stack.peek();
		}

		public ActionEvent pop() {
			return stack.pop();
		}

		public ActionEvent remove(int i) {
			return stack.remove(i);
		}

		public LimitedtStack(int limit) {
			this.islimited = true;
			this.limit = limit;
			stack.setSize(limit);
		}

		public void push(ActionEvent event) {
			if (islimited && stack.size() >= limit && !stack.isEmpty()) {
				// throws the low element of the stack
				stack.remove(0);
			}
			stack.push(event);
		}

		@Override
		public String toString() {
			return stack.toString();
		}
	}

	public static void main(String[] args) {
		// tests
		ActionTracer s = new ActionTracer(4);
		for (int i = 1; i < 10; i++) {
			try {
				s.push(null,null,"i=" + i);
			} catch (Exception e) {
				e.printStackTrace();
			}
			System.out.println(i + "=" + s.stack);
		}

		System.out.println("fim=" + s.stack);
	}

}